#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <fstream>
#include <sstream>
using namespace std;

class Dwarf
{
public:
    enum Type
    {
        Unknown = -1, 
        Farmer = 0, 
        Warrior, 
        Craftsman, 
        Miner, 
    };

    Dwarf(Type type)
        : m_type(type)
    {
    }
    virtual ~Dwarf()
    {
    }

    Type GetType() const
    {
        return m_type;
    }

    bool Right() const
    {
        cout << "Turning right" << endl;
        return true;
    }
    bool Left() const
    {
        cout << "Turning left" << endl;
        return true;
    }
    bool Forward() const
    {
        cout << "Turning forward" << endl;
        return true;
    }
    bool Backward() const
    {
        cout << "Turning backward" << endl;
        return true;
    }
    bool Say() const
    {
        cout << "Hi" << endl;
        return true;
    }
    bool Go() const
    {
        cout << "Moving" << endl;
        return true;
    }
    bool Stop() const
    {
        cout << "Stopped" << endl;
        return true;
    }
    bool Attack() const
    {
        if (m_type == Warrior)
        {
            cout << "Attacking" << endl;
        }
        else
        {
            cout << "I\'m not a warrior" << endl;
            return false;
        }

        return true;
    }
    bool Work() const
    {
        if ((m_type == Farmer) || (m_type == Craftsman) || 
            (m_type == Miner))
        {
            cout << "Working" << endl;
        }
        else
        {
            cout << "My work is attacking" << endl;
            return false;
        }

        return true;
    }

protected:
    Type m_type;
};

void ReadLineFromConsole(string& result)
{
    result = "";
    cin.clear();
    cout << ">";
    getline(cin, result);
}

Dwarf ChooseDwarf()
{
    cout << "Choose dwarf\'s type (farmer, warrior, craftsman, miner):" << endl;

    bool dwarfSelected = false;
    Dwarf::Type dwarfType = Dwarf::Unknown;
    string input;

    while (cin && !dwarfSelected)
    {
        ReadLineFromConsole(input);
        if (input == "farmer")
        {
            dwarfType = Dwarf::Farmer;
            dwarfSelected = true;
        }
        else if (input == "warrior")
        {
            dwarfType = Dwarf::Warrior;
            dwarfSelected = true;
        }
        else if (input == "craftsman")
        {
            dwarfType = Dwarf::Craftsman;
            dwarfSelected = true;
        }
        else if (input == "miner")
        {
            dwarfType = Dwarf::Miner;
            dwarfSelected = true;
        }
        else
        {
            cout << "Wrong type" << endl;
        }
    }

    if (dwarfSelected)
    {
        cout << "Dwarf selected" << endl;
    }
    else
    {
        cout << "Dwarf not selected" << endl;
    }
    cout << endl;

    return Dwarf(dwarfType);
}

const string RIGHT = "right", 
    LEFT = "left", 
    FORWARD = "forward", 
    BACKWARD = "backward", 
    SAY = "say", 
    GO = "go", 
    STOP = "stop", 
    ATTACK = "attack", 
    WORK = "work", 
    REPETITION = "while", 
    READ_FILE = "file";

bool ExecuteDwarfCommand(Dwarf& dwarf, const string& cmd)
{
    if (cmd == RIGHT)
    {
        dwarf.Right();
    }
    else if (cmd == LEFT)
    {
        dwarf.Left();
    }
    else if (cmd == FORWARD)
    {
        dwarf.Forward();
    }
    else if (cmd == BACKWARD)
    {
        dwarf.Backward();
    }
    else if (cmd == SAY)
    {
        dwarf.Say();
    }
    else if (cmd == GO)
    {
        dwarf.Go();
    }
    else if (cmd == STOP)
    {
        dwarf.Stop();
    }
    else if (cmd == ATTACK)
    {
        dwarf.Attack();
    }
    else if (cmd == WORK)
    {
        dwarf.Work();
    }
    else
    {
        return false;
    }

    return true;
}

bool IsCommand(const string& cmd)
{
    if (cmd == RIGHT || cmd == LEFT || cmd == FORWARD || 
        cmd == BACKWARD || cmd == SAY || cmd == GO || 
        cmd == STOP || cmd == ATTACK || cmd == WORK)
    {
        return true;
    }

    return false;
}

bool IsVarNameCorrect(const string& name)
{
    for (size_t i = 0; i < name.length(); ++i)
    {
        char ch = name[i];
        if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
        {
            return false;
        }
    }

    return true;
}

string TrimSpaces(const string& str)
{
    size_t startPos = 0, endPos = str.length() - 1;
    while (str[startPos] == ' ')
    {
        ++startPos;
    }
    while (str[endPos] == ' ')
    {
        --endPos;
    }
    return str.substr(startPos, endPos - startPos + 1);
}

void SplitLineToCommands(const string& line, vector<string>& commands)
{
    commands.clear();
    size_t prevPos = 0, semicolonPos = line.find(";");
    if (semicolonPos == string::npos)
    {
        commands.push_back(line);
    }
    else
    {
        while (semicolonPos != string::npos)
        {
            string singleCommand = line.substr(prevPos, semicolonPos - prevPos);
            commands.push_back(TrimSpaces(singleCommand));
            prevPos = semicolonPos + 1;
            semicolonPos = line.find(";", prevPos);
        }
    }
}

bool DoCommand(Dwarf& dwarf, string& cmd);

void ExecuteCommands(Dwarf& dwarf, vector<string>& commands)
{
    bool err = false;
    for (size_t i = 0; i < commands.size(); ++i)
    {
        err = !DoCommand(dwarf, commands[i]);

        if (err)
        {
            if (cin)
            {
                cout << "Wrong command (" << commands[i] << ")" << endl;
            }
        }
    }
}

bool DoCommand(Dwarf& dwarf, string& cmd)
{
    string input;
    stringstream inputStream(cmd);
    inputStream >> input;

    if (IsCommand(input))
    {
        ExecuteDwarfCommand(dwarf, input);
    }
    else if (input == REPETITION)
    {
        string var, command;
        if (!(inputStream >> var >> command))
        {
            return false;
        }

        if ((var[0] != '(') || 
            (var[var.length() - 1] != ')'))
        {
            return false;
        }

        if (!IsVarNameCorrect(var.substr(1, var.length() - 2)))
        {
            return false;
        }

        if (!IsCommand(command))
        {
            return false;
        }

        for (int i = 0; i < 5; ++i)
        {
            ExecuteDwarfCommand(dwarf, command);
        }
    }
    else if (input == READ_FILE)
    {
        string fileName;
        inputStream >> fileName;
        ifstream f(fileName.c_str());
        if (!f.good())
        {
            cout << "File doesn\'t exists" << endl;
            return true;
        }

        string fline;
        while (getline(f, fline))
        {
            vector<string> commands;
            SplitLineToCommands(fline, commands);
            ExecuteCommands(dwarf, commands);
        }
    }
    else
    {
        return false;
    }

    return true;
}

void Interact(Dwarf& dwarf)
{
    cout << "  Allowed commands: " << endl << RIGHT << ", " << LEFT 
        << ", " << FORWARD << ", " << BACKWARD << ", " << SAY 
        << ", " << GO << ", " << endl << STOP << ", " << ATTACK 
        << ", " << WORK << ", " << REPETITION << " (<var>) <command>" << endl;
    cout << "  To read commands from file, write: " << endl 
        << READ_FILE << " filename" << endl;
    cout << endl;

    string line;
    while (cin)
    {
        ReadLineFromConsole(line);

        vector<string> commands;
        SplitLineToCommands(line, commands);
        ExecuteCommands(dwarf, commands);
    }
    cout << endl;
}

int main(int argc, char* argv[])
{
    Dwarf dwarf = ChooseDwarf();
    if (dwarf.GetType() != Dwarf::Unknown)
    {
        Interact(dwarf);
    }

    cout << "Good bye" << endl;

    return 0;
}
























